home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Add-On
/
Workbench Add-On - Volume 1.iso
/
BBS-Archive
/
Comm
/
AmiTCP30b2.lha
/
src
/
amitcp
/
kern
/
amiga_log.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-05-02
|
20KB
|
731 lines
RCS_ID_C="$Id: amiga_log.c,v 1.41 1994/05/02 19:59:24 jraja Exp $";
/*
* Copyright (c) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>,
* Helsinki University of Technology, Finland.
* All rights reserved.
*
* HISTORY
* $Log: amiga_log.c,v $
* Revision 1.41 1994/05/02 19:59:24 jraja
* Removed not-used local variable.
*
* Revision 1.40 1994/04/22 13:55:46 jraja
* Fixed the bug in log file/console name change notify function:
* NATTRACE's DosBase is no more used before initialization.
*
* Revision 1.39 1994/02/17 18:21:54 jraja
* Changed vcsprintf to csprintf.
*
* Revision 1.38 1994/02/16 21:49:02 jraja
* Changed log date formatting to use vcsprintf() with '32-bit' formatting.
*
* Revision 1.37 1994/01/23 22:04:57 jraja
* Fixed void return on log_task().
*
* Revision 1.36 1994/01/19 21:39:17 jraja
* Added Seek()ing to the end of the old log file if necessary.
*
* Revision 1.35 1994/01/05 10:07:36 jraja
* Made ARexx port visible only after API is visible.
* Moved IntuitionBase open&close to the panic() function.
* Added static variables for the memory (addrs&sizes) allocated, so that
* FreeMem() would not crash if configuration is changed.
* General code & comments clean-up.
*
* Revision 1.34 1993/11/14 19:46:43 jraja
* Fixed off-by-one errors in month & day names.
*
* Revision 1.33 1993/11/06 23:51:22 ppessi
* Changed log message format. Converted to use csprintf where possible.
*
* Revision 1.31 1993/10/07 22:41:34 ppessi
* Added time to the log message.
*
* Revision 1.30 1993/08/06 08:58:37 jraja
* Set required bsdsocket.library version to 2.
*
* Revision 1.29 1993/06/04 11:16:15 jraja
* Fixes for first public release.
*
* Revision 1.28 1993/06/01 08:38:04 puhuri
* Fixed declaration of logOpen. (missing static)
*
* Revision 1.27 1993/05/27 16:43:26 puhuri
* Made better file opening (now tries everything).
* Add few commets.
*
* Revision 1.26 1993/05/17 01:07:47 ppessi
* Changed RCS version.
*
* Revision 1.25 1993/05/05 16:10:02 puhuri
* Fixes for final demo.
*
* Revision 1.24 93/05/04 12:41:31 12:41:31 puhuri (Markus Peuhkuri)
* Fixed defination of stuffchar(), perdence errors.
*
* Revision 1.23 93/05/03 18:47:48 18:47:48 puhuri (Markus Peuhkuri)
* Add check to GetLogMsg to avoid calling GetMsg with NULL pointer
* (So we can call log before NETTRACE is activated, it just does not
* success) It also tries to open socket.library when it gots CTRL-F.
*
* Revision 1.22 93/04/29 22:02:04 22:02:04 puhuri (Markus Peuhkuri)
* Moved configuration structure log_cnf to amiga_log.h
*
* Revision 1.21 93/04/28 19:24:30 19:24:30 puhuri (Markus Peuhkuri)
* Fixed variables to give reliable configuration.
*
* Revision 1.20 93/04/26 20:34:28 20:34:28 puhuri (Markus Peuhkuri)
* Converts control-charactes to spaces, Add ability to modify
* console and log filenames.
*
* Revision 1.19 93/04/26 18:52:07 18:52:07 puhuri (Markus Peuhkuri)
* Moved closelog() from subr_prf inside of log_deinit() as it was the
* only place where it was calld. (Was for historial reasons)
* Moved closing of Dos earlier in log_close to avoid problems in closing.
*
* Revision 1.18 93/04/23 02:27:44 02:27:44 ppessi (Pekka Pessi)
* Number and length of logging messages made configreable.
*
* Revision 1.17 93/04/21 19:05:26 19:05:26 puhuri (Markus Peuhkuri)
* Removed panic()'s if log file couldn't be opened/wroted. Add comments.
* Now uses new structure of log_msg.
*
* Revision 1.16 93/04/20 18:38:01 18:38:01 puhuri (Markus Peuhkuri)
* Fixed prototype of log_poll, logmask was number of signal, not mask.
* pointers to *file were automatic variables, now static.
*
* Revision 1.15 93/04/17 17:56:29 17:56:29 puhuri (Markus Peuhkuri)
* Fixed few trivial errors from previous version.
* (Should compile before ci)
*
* Revision 1.14 93/04/17 17:16:51 17:16:51 puhuri (Markus Peuhkuri)
* Moved REXX-stuff to NETTRACE-task (from amiga_main)
*
* Revision 1.13 93/04/06 15:15:30 15:15:30 jraja (Jarno Tapio Rajahalme)
* Changed spl function return value storage to spl_t,
* changed bcopys and bzeros to aligned and/or const when possible,
* added inclusion of conf.h to every .c file.
*
* Revision 1.12 93/03/20 07:07:11 07:07:11 ppessi (Pekka Pessi)
* Fixed memory leak caused by task_remove()
*
* Revision 1.11 93/03/12 23:59:17 23:59:17 ppessi (Pekka Pessi)
* Prototype fixes.
*
* Revision 1.10 93/03/09 13:29:26 13:29:26 puhuri (Markus Peuhkuri)
* Now stores information of failed log attempts using new function
* GetLogMsg. (Increments the number of failed, which is then printed
* (and zeroed) as logging task gets next message (ts handles it))
*
* Revision 1.9 93/03/05 21:10:51 21:10:51 jraja (Jarno Tapio Rajahalme)
* Fixed includes (again).
*
* Revision 1.8 93/03/05 12:26:58 12:26:58 jraja (Jarno Tapio Rajahalme)
* Added CloseLibrary() calls to close logDOSBase on exit.
*
* Revision 1.7 93/03/05 03:25:45 03:25:45 ppessi (Pekka Pessi)
* Compiles with SASC. Initial test version.
*
* Revision 1.6 93/03/04 10:03:51 10:03:51 jraja (Jarno Tapio Rajahalme)
* Fixed includes.
*
* Revision 1.5 93/03/01 19:09:39 19:09:39 puhuri (Markus Peuhkuri)
* Add variable.
*
* Revision 1.4 93/02/26 19:42:46 19:42:46 puhuri (Markus Peuhkuri)
* Modified to use MsgPort as list of free messages.
*
* Revision 1.3 93/02/25 19:33:55 19:33:55 puhuri (Markus Peuhkuri)
* Cleanup and consistency with other modules, removed amiga.lib stuff,
* made compatible with SAS, log task has own DOSBase
*
*/
#include <conf.h>
#include <bsdsocket.library_rev.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <exec/exec.h>
#include <dos/dos.h>
#include <dos/dostags.h>
#include <dos/dosextens.h>
#include <kern/amiga_includes.h>
#include <sys/syslog.h>
#include <kern/amiga_log.h>
#include <kern/amiga_rexx.h>
#include <utility/date.h>
#if __SASC
#include <proto/dos.h>
#include <proto/utility.h>
#elif __GNUC__
#define DOSBase logDOSBase
#define UtilityBase logUtilityBase
#include <inline/dos.h>
#undef DOSBase
#else
#error Compiler not supported!
#endif
struct MsgPort *logPort,*logReplyPort;
static struct Library *logDOSBase = NULL;
static struct Library *logUtilityBase = NULL;
extern struct Task *AmiTCP_Task;
extern struct DosLibrary *DOSBase;
extern void REGARGFUN stuffchar();
extern int logname_changed(void *p, LONG new);
static struct log_msg *log_poll(void);
static void log_task(void);
static void log_close(struct log_msg *msg);
static BPTR logOpen(STRPTR name);
static struct log_msg *log_messages = NULL;
static char *log_buffers = NULL;
static LONG log_messages_mem_size, log_buffers_mem_size;
static int GetLogMsgFail;
UBYTE consoledefname[] = _PATH_CON;
UBYTE logfiledefname[] = _PATH_LOG;
STRPTR logfilename = logfiledefname;
STRPTR consolename = consoledefname;
struct log_cnf log_cnf = { LOG_BUFS, LOG_BUF_LEN };
/*
* Initialization function for the logging subsystem
*/
BOOL
log_init(void)
{
struct Message *msg;
int i;
ULONG sig;
if (logReplyPort)
return(TRUE); /* We're allready initialized */
/*
* Allocate buffers for log messages.
*
* Save lengths to static variables, since the configuration variables might
* change.
*/
log_messages_mem_size = sizeof(struct log_msg) * log_cnf.log_bufs;
log_buffers_mem_size = log_cnf.log_bufs * log_cnf.log_buf_len * sizeof(char);
if (log_messages = AllocMem(log_messages_mem_size, MEMF_CLEAR|MEMF_PUBLIC))
if (log_buffers = AllocMem(log_buffers_mem_size, MEMF_CLEAR|MEMF_PUBLIC)) {
logPort = NULL; /* NETTRACE will set this on success */
GetLogMsgFail = 0;
if (logReplyPort = CreateMsgPort()) {
/*
* Start the NETTRACE process
*/
if (CreateNewProcTags(NP_Entry, (LONG)&log_task,
NP_Name, (LONG)LOG_TASK_NAME,
NP_Priority, LOG_TASK_PRI,
TAG_DONE, NULL)) {
for (;;) {
/*
* Wait for a signal for success or failure
*/
sig = Wait(1<<logReplyPort->mp_SigBit | SIGBREAKF_CTRL_F);
if (sig & SIGBREAKF_CTRL_F && logPort == (struct MsgPort *)-1) {
/* Initializion failed */
logPort = NULL;
break;
}
else if (msg = GetMsg(logReplyPort)) { /* Got message back? */
ReplyMsg(msg);
logReplyPort->mp_Flags = PA_IGNORE;
/*
* Initialize messages
*/
for (i = 0; i < log_cnf.log_bufs; i++) {
log_messages[i].msg.mn_ReplyPort = logReplyPort;
log_messages[i].msg.mn_Length = sizeof(struct log_msg);
log_messages[i].level = 0;
log_messages[i].string = log_buffers+i*log_cnf.log_buf_len;
log_messages[i].chars = 0;
PutMsg(logReplyPort, (struct Message *)&log_messages[i]);
}
return(TRUE); /* We're done */
}
}
}
}
}
/*
* Something went wrong
*/
log_deinit();
return(FALSE);
}
/*
* This function may be called only if no other tasks (applications) are
* accessing the logging system (the messages, to be exact).
*/
void
log_deinit(void)
{
struct log_msg *msg, *dump;
if (logReplyPort) { /* We have our port? */
if (logPort) { /* Logport exists? (=> NETTRACE is running) */
/*
* Turn on signalling on returned messages again
*/
logReplyPort->mp_Flags = PA_SIGNAL;
/*
* Get a free message, Wait() for it if necessary
*/
while((msg = (struct log_msg *)GetMsg(logReplyPort)) == NULL)
Wait(1<<logReplyPort->mp_SigBit);
/*
* Initalize END_MESSAGE
*/
msg->msg.mn_ReplyPort = logReplyPort;
msg->msg.mn_Length = sizeof(struct log_msg);
msg->level = LOG_CLOSE;
PutMsg(logPort, (struct Message *)msg);
for (;;) {
dump = (struct log_msg *)GetMsg(logReplyPort);
if (dump) {
if (dump->level == LOG_CLOSE) /* got the Close message back */
break; /* It was the last one */
}
else
Wait(1<<logReplyPort->mp_SigBit);
}
}
/*
* ensure that the port is empty
*/
while(GetMsg(logReplyPort))
;
DeleteMsgPort(logReplyPort);
logReplyPort = NULL;
}
if (log_buffers) {
FreeMem(log_buffers, log_buffers_mem_size);
log_buffers = NULL;
}
if (log_messages) {
FreeMem(log_messages, log_messages_mem_size);
log_messages = NULL;
}
}
/* A little stub for calling GetMsg w/ error reporting and cheking */
struct log_msg *GetLogMsg(struct MsgPort *port)
{
struct Message *msg;
if (port && (msg = GetMsg(port))) /* Get a message */
/* We should have a port, if not-> fail */
return (struct log_msg *)msg;
++GetLogMsgFail; /* Increment number of failed messages */
return NULL;
}
/*
* Functions following these defines may be called from the NETTRACE
* task ONLY! These defines cause the SAS/C to generate calls to
* dos.library and utility.library using these bases, respectively.
*/
#define DOSBase logDOSBase
#define UtilityBase logUtilityBase
struct Library *SocketBase = NULL;
struct Task *Nettrace_Task = NULL;
/* Main loop for NETTRACE */
static void SAVEDS
log_task(void)
{
struct log_msg *initmsg = NULL;
ULONG rexxmask = 0, logmask = 0, sigmask = 0;
Nettrace_Task = FindTask(NULL); /* Store task pointer for AmiTCP */
/* We need our own DosBase */
if ((logDOSBase = OpenLibrary(DOSNAME, 0L)) == NULL)
goto fail;
if ((logUtilityBase = OpenLibrary("utility.library", 37L)) == NULL)
goto fail;
/* Allocate message to reply startup */
if ((initmsg = AllocMem(sizeof(struct log_msg), MEMF_CLEAR|MEMF_PUBLIC))
== NULL)
goto fail;
/* Create our port for log messages */
if ((logPort = CreateMsgPort()) == NULL)
goto fail;
logmask = 1<<logPort->mp_SigBit;
/*
* Initialize rexx subsystem
*/
if (!(rexxmask = rexx_init()))
goto fail;
/*
* Syncronize with AmiTCP/IP
*/
initmsg->msg.mn_ReplyPort = logPort;
initmsg->msg.mn_Length = sizeof(struct log_msg);
PutMsg(logReplyPort, (struct Message *)initmsg);
do {
Wait(logmask);
} while(initmsg != (struct log_msg *)GetMsg(logPort));
FreeMem(initmsg, sizeof(struct log_msg));
initmsg = NULL;
sigmask = logmask | rexxmask | SIGBREAKF_CTRL_F;
/*
* Main loop of the NETTRACE
*/
for (;;) {
ULONG sig;
struct log_msg *msg;
sig = Wait(sigmask); /* Wait for signals */
do {
/* Signal from the AmiTCP/IP: API ready */
if ((sig & SIGBREAKF_CTRL_F) && (SocketBase == NULL)) {
sig &= ~SIGBREAKF_CTRL_F;
/*
* Open a base to our own library so that ARexx message handling
* can use socket functions.
* This name does not work with the "nthLibrary" system
*/
if (SocketBase = OpenLibrary("bsdsocket.library", VERSION)) {
/*
* Make our ARexx port public
*/
rexx_show();
sigmask &= ~SIGBREAKF_CTRL_F;
}
}
if (sig & logmask) { /* Process log messages,
* handles all ones pending.
*/
if (msg = log_poll()) { /* Got an LOG_CLOSE-message? */
log_close(msg);
return;
}
sig &= ~logmask;
}
if (sig & rexxmask) /* One rexx message at time */
if (SocketBase) {
if (!rexx_poll())
sig &= ~rexxmask;
} else
sig &= ~rexxmask;
sig |= SetSignal(0L, sigmask) & sigmask; /* Signals left? */
} while (sig);
}
fail:
/* Initializion Failed */
if (initmsg)
FreeMem(initmsg, sizeof(struct log_msg));
log_close(NULL);
logPort = (struct MsgPort *)-1;
/* Inform AmiTCP that we failed */
Signal(AmiTCP_Task, SIGBREAKF_CTRL_F);
}
static BPTR confile = NULL;
static BPTR logfile = NULL;
static BOOL fileopenfail = FALSE, conopenfail = FALSE;
static BOOL filewritefail = FALSE, conwritefail = FALSE;
static char *months =
"Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec";
static char *wdays =
"Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat";
static char *levels =
"emerg\0"
"alert\0"
"crit \0"
"err \0"
"warn \0"
"note \0"
"info \0"
"debug";
/*
* Process all pending log messages
*/
static
struct log_msg *log_poll()
{
struct log_msg *msg;
ULONG where;
LONG i;
struct ClockData clockdata;
/* 28 for date, 14 for level */
# define LEVELBUF 28+14
UBYTE buffer[LEVELBUF];
static ULONG TotalFail;
/* Process all messages */
while (msg = (struct log_msg *)GetMsg(logPort)) {
struct CSource cs;
/* All except LOG_EMERG to both log and console */
where = TOLOG;
if (msg->level != LOG_EMERG)
where |= TOCONS;
if (msg->level == LOG_CLOSE) {
return (msg);
}
cs.CS_Buffer = buffer;
cs.CS_Length = LEVELBUF;
cs.CS_CurChr = 0;
Amiga2Date(msg->time, &clockdata);
csprintf(&cs,
#ifdef HAVE_TIMEZONES
"%s %s %02d %02d:%02d:%02d %s %4d [%s]: ",
#else
"%s %s %02d %02d:%02d:%02d %4d [%s]: ",
#endif
wdays + 4 * clockdata.wday,
months + 4 * (clockdata.month - 1),
clockdata.mday,
clockdata.hour,
clockdata.min,
clockdata.sec,
#ifdef HAVE_TIMEZONES
"UCT", /* Universal Coordinated Time */
#endif
clockdata.year,
levels + 6 * ((msg->level <= LOG_DEBUG) ? msg->level : LOG_DEBUG)
);
/* Remove last newline */
if (msg->chars > 0 && msg->string[msg->chars - 1] == '\n') {
msg->chars--;
}
/* Replace all control chars with space */
for (i = 0; i < msg->chars; ++i) {
if ((msg->string)[i] < ' ')
(msg->string)[i] = ' ';
}
if (where & TOCONS) {
/* If console is not open, open it */
while (confile == NULL) {
if ((confile = logOpen(consolename)) == NULL) {
if (!conopenfail) /* log only once */
log(LOG_ERR,"Opening console log '%s' failed", consolename);
if (consolename == consoledefname) {
conopenfail = TRUE;
break;
}
/* try again with the default name */
consolename = consoledefname;
conopenfail = conwritefail = FALSE;
}
}
if (confile != NULL) {
int error =
FPuts(confile, buffer) == -1 ||
FWrite(confile, msg->string, msg->chars, 1) != 1 ||
FPutC(confile, '\n') == -1;
Flush(confile);
if (error && !conwritefail) { /* To avoid loops */
conwritefail = TRUE;
log(LOG_ERR, "log: Write failed to console '%s'", consolename);
}
}
}
if (where & TOLOG) {
/* If log file is not open, open it */
while (logfile == NULL) {
if ((logfile = logOpen(logfilename)) == NULL) {
if (!fileopenfail) /* log only once */
log(LOG_ERR,"Opening log file '%s' failed", logfilename);
if (logfilename == logfiledefname) {
fileopenfail = TRUE;
break;
}
/* try again with the default name */
logfilename = logfiledefname;
fileopenfail = filewritefail = FALSE;
}
}
if (logfile != NULL) {
int error =
FPuts(logfile, buffer) == -1 ||
FWrite(logfile, msg->string, msg->chars, 1) != 1 ||
FPutC(logfile, '\n') == -1;
Flush(logfile);
if (error && !filewritefail) { /* To avoid loops */
filewritefail = TRUE;
log(LOG_ERR, "log: Write failed to file '%s'", logfilename);
}
}
}
ReplyMsg((struct Message *)msg);
if (GetLogMsgFail != TotalFail) {
int t = GetLogMsgFail; /* Check if we have lost messages */
log(LOG_WARNING,"%ld log messages lost (total %ld lost)\n",
t - TotalFail, TotalFail);
TotalFail = t;
}
}
return(NULL);
}
/* Close logging subsystem */
static
void log_close(struct log_msg *msg)
{
rexx_deinit();
if (confile)
Close(confile);
if (logfile)
Close(logfile);
if (logUtilityBase) {
CloseLibrary(logUtilityBase);
logUtilityBase = NULL;
}
if (logDOSBase) { /* DOS not needed below */
CloseLibrary(logDOSBase);
logDOSBase = NULL;
}
if (SocketBase) {
CloseLibrary((struct Library *)SocketBase);
SocketBase = NULL;
}
/*
* Make sure that we get to end before task switch
* and do not get messages from interrupts
*/
Disable();
if (logPort) {
struct Message *m;
while (m = GetMsg(logPort)) /* Check for messages and reply */
ReplyMsg(m);
DeleteMsgPort(logPort); /* Delete port */
logPort = NULL;
}
if (msg)
ReplyMsg((struct Message *)msg);
Nettrace_Task = NULL;
/*
* Interrupts are left disabled,
* they will be enabled again when this process dies
*/
}
/*
* Try first open w/ shared lock, then as an old file and finally as a new file
*/
static
BPTR logOpen(STRPTR name)
{
BPTR file;
if ((file = Open(name, MODE_READWRITE)) ||
(file = Open(name, MODE_OLDFILE)))
Seek(file, 0, OFFSET_END);
else
file = Open(name, MODE_NEWFILE);
return file;
}
/*
* This function might be called by either AmiTCP or NETTRACE. If the
* call is done by the AmiTCP, no DOS calls may be done, since the
* DosBase used by these functions is the one of the NETTRACE, and is
* not initialized at that time!
*/
int logname_changed(void *p, LONG new)
{
if (p == &logfilename) { /* Is logname requested? */
/*
* logfile may be non-NULL only if the NETTRACE is already initialized
*/
if (logfile != NULL) {
Close(logfile);
logfile = NULL;
}
fileopenfail = filewritefail = FALSE;
/*
* setvalue() (who called this) will set the new value when we return
* TRUE.
*/
return TRUE;
}
if ( p == &consolename ) { /* Name of the console log */
if (confile) { /* only if NETTRACE is already initialized */
Close(confile);
confile = NULL;
}
conopenfail = conwritefail = FALSE;
/*
* setvalue() (who called this) will set the new value when we return
* TRUE.
*/
return TRUE;
}
/*
* Some invalid pointer
*/
return FALSE;
}